package nape.shape;
import zpp_nape.Config;
import zpp_nape.Const;
import zpp_nape.util.Flags;
import DummyNapeMain;
import zpp_nape.util.Math;
import zpp_nape.util.Names;
import zpp_nape.util.Pool;
import zpp_nape.util.Lists;
import zpp_nape.shape.Circle;
import zpp_nape.shape.Edge;
import zpp_nape.space.Space;
import zpp_nape.shape.Polygon;
import zpp_nape.shape.Shape;
import zpp_nape.phys.FeatureMix;
import zpp_nape.phys.FluidProperties;
import zpp_nape.phys.Material;
import zpp_nape.phys.Body;
import zpp_nape.geom.AABB;
import zpp_nape.geom.Distance;
import zpp_nape.geom.Mat23;
import zpp_nape.geom.Vec2;
import zpp_nape.geom.VecMath;
import zpp_nape.geom.Collide;
import zpp_nape.dynamics.Arbiter;
import zpp_nape.dynamics.Contact;
import zpp_nape.dynamics.InteractionFilter;
import zpp_nape.constraint.Constraint;
import zpp_nape.dynamics.SpaceArbiterList;
import zpp_nape.constraint.Matrices;
import zpp_nape.constraint.PivotJoint;
import zpp_nape.constraint.WeldJoint;
import nape.util.Flags;
import nape.util.Lists;
import nape.util.Debug;
import nape.space.Space;
import nape.shape.Circle;
import nape.shape.Edge;
import nape.shape.Shape;
import nape.phys.FluidProperties;
import nape.phys.Material;
import nape.phys.Body;
import nape.geom.AABB;
import nape.geom.Geom;
import nape.geom.Mat23;
import nape.geom.Vec2;
import nape.dynamics.Contact;
import nape.dynamics.Arbiter;
import nape.dynamics.InteractionFilter;
#if swc@:keep#end class ValidationResult{
    public function new(){
        if(!ZPP_Flags.internal)throw "Error: Cannot instantiate "+"ValidationResult"+" derp!";
    }
    @:keep inline public function toString(){
        if(false)return "";
        
        else if(this==CONCAVE)return"CONCAVE";
        else if(this==DEGENERATE)return"DEGENERATE";
        else if(this==DEGENERATE_EDGES)return"DEGENERATE_EDGES";
        else if(this==SELF_INTERSECTING)return"SELF_INTERSECTING";
        else if(this==VALID)return"VALID";
        else return "";
    }
    public static var VALID(flibget_VALID,never):ValidationResult;
    inline static function flibget_VALID(){
        if(ZPP_Flags.ValidationResult_VALID==null){
            ZPP_Flags.internal=true;
            ZPP_Flags.ValidationResult_VALID=new ValidationResult();
            ZPP_Flags.internal=false;
        }
        return ZPP_Flags.ValidationResult_VALID;
    }
    public static var DEGENERATE(flibget_DEGENERATE,never):ValidationResult;
    inline static function flibget_DEGENERATE(){
        if(ZPP_Flags.ValidationResult_DEGENERATE==null){
            ZPP_Flags.internal=true;
            ZPP_Flags.ValidationResult_DEGENERATE=new ValidationResult();
            ZPP_Flags.internal=false;
        }
        return ZPP_Flags.ValidationResult_DEGENERATE;
    }
    public static var DEGENERATE_EDGES(flibget_DEGENERATE_EDGES,never):ValidationResult;
    inline static function flibget_DEGENERATE_EDGES(){
        if(ZPP_Flags.ValidationResult_DEGENERATE_EDGES==null){
            ZPP_Flags.internal=true;
            ZPP_Flags.ValidationResult_DEGENERATE_EDGES=new ValidationResult();
            ZPP_Flags.internal=false;
        }
        return ZPP_Flags.ValidationResult_DEGENERATE_EDGES;
    }
    public static var CONCAVE(flibget_CONCAVE,never):ValidationResult;
    inline static function flibget_CONCAVE(){
        if(ZPP_Flags.ValidationResult_CONCAVE==null){
            ZPP_Flags.internal=true;
            ZPP_Flags.ValidationResult_CONCAVE=new ValidationResult();
            ZPP_Flags.internal=false;
        }
        return ZPP_Flags.ValidationResult_CONCAVE;
    }
    public static var SELF_INTERSECTING(flibget_SELF_INTERSECTING,never):ValidationResult;
    inline static function flibget_SELF_INTERSECTING(){
        if(ZPP_Flags.ValidationResult_SELF_INTERSECTING==null){
            ZPP_Flags.internal=true;
            ZPP_Flags.ValidationResult_SELF_INTERSECTING=new ValidationResult();
            ZPP_Flags.internal=false;
        }
        return ZPP_Flags.ValidationResult_SELF_INTERSECTING;
    }
}
#if swc@:keep#end class Polygon extends Shape{
    public var zpp_inner_zn:ZPP_Polygon;
    #if swc@:keep#end public static function copy(polygon:Polygon){
        if(polygon==null)throw "Error: Cannot copy null polygon";
        return polygon.zpp_inner.copy().polygon;
    }
    #if swc@:keep#end public static inline function rect(x:Float,y:Float,width:Float,height:Float){
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](x);
            ret;
            #else Math.isNaN(x);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](y);
            ret;
            #else Math.isNaN(y);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](width);
            ret;
            #else Math.isNaN(width);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](height);
            ret;
            #else Math.isNaN(height);
            #end
        }))throw "Error: Polygon.rect cannot accept NaN arguments";
        return[new Vec2(x,y),new Vec2(x+width,y),new Vec2(x+width,y+height),new Vec2(x,y+height)];
    }
    #if swc@:keep#end public static inline function box(width:Float,height:Float){
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](width);
            ret;
            #else Math.isNaN(width);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](height);
            ret;
            #else Math.isNaN(height);
            #end
        }))throw "Error: Polygon.box cannot accept NaN arguments";
        return rect(-width/2,-height/2,width,height);
    }
    #if swc@:keep#end public static inline function regular(width:Float,height:Float,edgeCount:Int,?angleOffset=0.0){
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](width);
            ret;
            #else Math.isNaN(width);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](height);
            ret;
            #else Math.isNaN(height);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](angleOffset);
            ret;
            #else Math.isNaN(angleOffset);
            #end
        }))throw "Error: Polygon.regular cannot accept NaN arguments";
        var ret=[];
        var dangle=Math.PI*2/edgeCount;
        for(i in 0...edgeCount){
            var ang=i*dangle+angleOffset;
            ret.push(new Vec2(Math.cos(ang)*width/2,Math.sin(ang)*height/2));
        }
        return ret;
    }
    public var localVerts(flibget_localVerts,never):Vec2List;
    inline function flibget_localVerts(){
        if(zpp_inner_zn.wrap_lverts==null)zpp_inner_zn.get_lverts();
        return zpp_inner_zn.wrap_lverts;
    }
    public var worldVerts(flibget_worldVerts,never):Vec2List;
    inline function flibget_worldVerts(){
        if(zpp_inner_zn.wrap_gverts==null)zpp_inner_zn.get_gverts();
        return zpp_inner_zn.wrap_gverts;
    }
    public var edges(flibget_edges,never):EdgeList;
    inline function flibget_edges(){
        if(zpp_inner_zn.wrap_edges==null)zpp_inner_zn.get_edges();
        return zpp_inner_zn.wrap_edges;
    }
    #if swc@:keep#end public function validity(){
        return zpp_inner_zn.valid();
    }
    public function new(localVerts:Dynamic,?material:Material,?filter:InteractionFilter){
        try{
            super();
        }
        catch(e:Dynamic){}
        if(localVerts==null)throw "Error: localVerts cannot be null";
        zpp_inner_zn=new ZPP_Polygon();
        zpp_inner_zn.outer=this;
        zpp_inner_zn.outer_zn=this;
        zpp_inner=zpp_inner_zn;
        if(Std.is(localVerts,Array)){
            var lv:Array<Dynamic>=localVerts;
            for(i in lv){
                if(i==null)throw "Error: localVerts contains null references";
                if(!Std.is(i,Vec2))throw "Error: localVerts contains non Vec2 instances";
                this.localVerts.push(i.copy());
            }
        }
        #if flash9 else if(Std.is(localVerts,flash.Vector)){
            var lv:flash.Vector<Dynamic>=localVerts;
            for(i in lv){
                if(i==null)throw "Error: localVerts contains null references";
                if(!Std.is(i,Vec2))throw "Error: localVerts contains non Vec2 instances";
                this.localVerts.push(i.copy());
            }
        }
        #end else if(Std.is(localVerts,Vec2List)){
            var lv:Vec2List=localVerts;
            for(i in lv){
                if(i==null)throw "Error: localVerts contains null references";
                this.localVerts.push(i.copy());
            }
        }
        else throw "Error: Invalid type for localVerts, should be Array<Vec2>, Vec2List or for flash9 flash.Vector<Vec2>";
        if(material==null){
            zpp_inner.material={
                if(ZPP_Material.zpp_pool==null)new ZPP_Material();
                else{
                    var ret=ZPP_Material.zpp_pool;
                    ZPP_Material.zpp_pool=ret.next;
                    ret;
                }
            };
            zpp_inner.material.addShape(this.zpp_inner);
        }
        else this.material=material;
        if(filter==null){
            zpp_inner.filter={
                if(ZPP_InteractionFilter.zpp_pool==null)new ZPP_InteractionFilter();
                else{
                    var ret=ZPP_InteractionFilter.zpp_pool;
                    ZPP_InteractionFilter.zpp_pool=ret.next;
                    ret;
                }
            };
            zpp_inner.filter.addShape(this.zpp_inner);
        }
        else this.filter=filter;
    }
}
